package com.ccp.dev.workflow.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.engine.FreemarkEngine;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.system.service.SysUserService;
import com.ccp.dev.workflow.bpmutil.ServiceUtil;
import com.ccp.dev.workflow.dao.ProcessRunDao;
import com.ccp.dev.workflow.dao.TaskOpinionDao;
import com.ccp.dev.workflow.model.ProcessRun;
import com.ccp.dev.workflow.model.TaskOpinion;
import com.ccp.dev.workflow.model.bpm.TaskExecutor;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * ClassDescribe:审批意见 Service类
 * @author :jiayueqiao
 * Date: 2019-10-21
 * Since:1
 */

@Service
public class TaskOpinionService extends BaseService<TaskOpinion> {
    protected static Logger logger = LoggerFactory.getLogger(BaseService.class);
    @Resource
    private TaskOpinionDao taskOpinionDao;
    @Resource
    private ProcessRunDao processRunDao;
    @Resource
    private ProcessRunService processRunService;
    @Resource
    private BpmService bpmService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private TaskUserService taskUserService;

    /**
     * 根据意见值获取意见
     * @param opinion 审批意见
     * @param isHtml 是否是html
     * @return 意见
     */
    public static String getOpinion(TaskOpinion opinion, boolean isHtml) {
        Map<String, Object> model = new HashMap<>(5);
        model.put("opinion", opinion);
        FreemarkEngine freemarkEngine = AppUtil.getBean(FreemarkEngine.class);
        String rtn = "";
        try {
            String template = isHtml ? "opinion.ftl" : "opiniontext.ftl";
            rtn = freemarkEngine.mergeTemplateIntoString(template, model);
            if (!isHtml) {
                rtn = rtn.replaceAll("</?[^>]+>", "");
            }
        } catch (Exception e) {
            logger.debug(e.getMessage());
        }
        return rtn;
    }

    /**
     * 根据实例id获取意见列表
     * @param instanceId 实例id
     * @return 意见列表
     */
    public List<TaskOpinion> getByProcInstId(String instanceId) {
        return getByProcInstId(instanceId, true);
    }

    /**
     * 取得某个任务的所有审批意见 按时间排序
     * @param procInstId 实例id
     * @param isAsc 是否升序
     * @return 意见列表
     */
    public List<TaskOpinion> getByProcInstId(String procInstId, boolean isAsc) {
        //取得顶级的流程实例ID
        String supInstId = getTopInstId(procInstId);

        List<String> procInstIds = new ArrayList<>();
        procInstIds.add(supInstId);
        //递归往下查询
        getChildInst(supInstId, procInstIds);
        Map<String,Object> params = new HashMap(2);
        params.put("procInstIds", procInstIds);
        params.put("isAsc", isAsc);
        return taskOpinionDao.getByProcInstId(params);
    }

    /**
     * 向上查询得到顶级的流程实例
     * @param procInstId 实例id
     * @return 顶级实例id
     */
    private String getTopInstId(String procInstId) {
        String rtn = procInstId;
        String supInstId = taskOpinionDao.getSupInstByProcInstId(procInstId);
        while (StringUtil.isNotEmpty(supInstId)) {
            rtn = supInstId;
            supInstId = taskOpinionDao.getSupInstByProcInstId(supInstId);
        }
        return rtn;
    }

    /**
     * 向下查询流程实例
     * @param supperId 父id
     * @param instList 子实例id列表
     */
    private void getChildInst(String supperId, List<String> instList) {
        List<TaskOpinion> list = taskOpinionDao.getBySupInstId(supperId);
        if (BeanUtils.isEmpty(list)) {
            return;
        }
        for (TaskOpinion taskOpinion : list) {
            String instId = taskOpinion.getProcInstId();
            instList.add(instId);
            getChildInst(instId, instList);
        }
    }

    /**
     * 获取正在审批的意见
     * @param procInstId 实例id
     * @return 意见列表
     */
    public List<TaskOpinion> getCheckOpinionByInstId(String procInstId) {
        return taskOpinionDao.getCheckOpinionByInstId(procInstId);
    }

    /**
     * 取得某个流程实例中，某用户最新的完成的审批记录
     *
     * @param procInstId 流程实例id
     * @param exeUserId 执行人id
     * @return TaskOpinion
     */
    public TaskOpinion getLatestUserOpinion(String procInstId, String exeUserId) {
        List<TaskOpinion> taskOpinions = taskOpinionDao.getByProcInstIdExeUserId(procInstId, exeUserId);
        if (taskOpinions.isEmpty()) {
            return null;
        }
        return taskOpinions.get(0);
    }
    /**
     * 取到最新的某个节点的审批记录
     * @param procInstId 流程实例id
     * @param taskKey 任务key
     * @return TaskOpinion
     */
    public TaskOpinion getLatestTaskOpinion(String procInstId, String taskKey) {
        List<TaskOpinion> taskOpinions = taskOpinionDao.getByProcInstIdTaskKey(procInstId, taskKey);
        if (taskOpinions.isEmpty()) {
            return null;
        }
        return taskOpinions.get(0);
    }
    /**
     * 取得对应该任务的执行
     *
     * @param taskId 任务id
     * @return TaskOpinion
     */
    public TaskOpinion getByTaskId(String taskId) {
        return taskOpinionDao.getByTaskId(taskId);
    }

    /**
     * 根据流程实例ID获取流程实例列表包括子流程实例。
     *
     * @param procInstId 实例id
     * @return Set&lt;String>
     */
    public Set<String> getInstListByInstId(String procInstId) {
        List<TaskOpinion> opinions = getByProcInstId(procInstId);
        Set<String> instSet = new HashSet<>();
        for (TaskOpinion opinion : opinions) {
            if (StringUtil.isNotEmpty(opinion.getProcInstId())) {
                instSet.add(opinion.getProcInstId());
            }
        }
        return instSet;
    }

    /**
     * 根据流程实例Id及任务定义Key取得审批列表
     *
     * @param procInstId 实例id
     * @param nodeId 节点id
     * @return list
     */
    public List<TaskOpinion> getByProcInstIdTaskKey(String  procInstId, String nodeId) {
        return taskOpinionDao.getByProcInstIdTaskKey(procInstId, nodeId);
    }

    /**
     * 根据实例节点获取任务实例状态。
     * @param procInstId 实例id
     * @param nodeId 节点id
     * @param checkStatus 状态
     * @return list
     */
    public List<TaskOpinion> queryByProcInstIdTaskKeyStatus(String  procInstId, String nodeId, Short checkStatus) {
        return taskOpinionDao.queryByProcInstIdTaskKeyStatus(procInstId, nodeId, checkStatus);
    }

    /**
     * 根据runId获取流程意见列表。
     * @param runId 运行id
     * @return list
     */
    public List<TaskOpinion> getByRunId(String runId) {
        List<String> procInstIdList=getProcessRunList(runId);
        List<TaskOpinion> list=new ArrayList<>();

        int len=procInstIdList.size();
        for(int i=len-1;i>=0;i--){
            String instId=procInstIdList.get(i);
            List<TaskOpinion> tmplist=getByProcInstId(instId);
            list.addAll(tmplist);
        }
        return list;
    }

    /**
     * 根据runId获取流程实例ID。
     * @param runId 运行id
     * @return list
     */
    private List<String> getProcessRunList(String runId){
        ProcessRun processRun= getTopProcessRun(runId);
        String tmpProcInstId= processRun.getProcInstId();

        List<String> list=new ArrayList<>();
        String relRunId=processRun.getRelRunId();
        //2020-01-03 jyq添加，当为流程草稿时tmpProcInstId为null
        if(null!=tmpProcInstId){
            list.add(tmpProcInstId);
        }
        String procDefId=processRun.getProcDefId();
        while(StringUtil.isNotEmpty(relRunId) ){
            ProcessRun tmpRun=processRunDao.getByHistoryId(relRunId);
            if(!procDefId.equals(tmpRun.getProcDefId())){
                break;
            }
            list.add(tmpRun.getProcInstId());
            relRunId=tmpRun.getRelRunId();
            procDefId=tmpRun.getProcDefId();
        }

        return list;
    }

    /**
     * 获取顶级流程实例。
     * @param runId 运行id
     * @return ProcessRun
     */
    private ProcessRun getTopProcessRun(String runId){
        ProcessRun	processRun=processRunService.getById(runId);
        String parentId=processRun.getParentId();
        while(StringUtil.isNotEmpty(parentId) ){
            processRun=processRunService.getById(parentId);
            parentId=processRun.getParentId();
        }
        return processRun;
    }

    public List<TaskOpinion> setTaskOpinionExecutor(List<TaskOpinion> opinions){
        for (TaskOpinion taskOpinion : opinions) {
            //正在审批
            if(taskOpinion.getCheckStatus().equals(TaskOpinion.STATUS_CHECKING)){
                TaskEntity task = bpmService.getTask(taskOpinion.getTaskId());
                if(BeanUtils.isNotEmpty(task) ){
                    //执行人不为空
                    String assignee=task.getAssignee();
                    if(ServiceUtil.isAssigneeNotEmpty(assignee)){
                        String fullName = "";
                        SysUser sysUser = sysUserService.getById(assignee);
                        if(BeanUtils.isNotEmpty(sysUser)){
                            fullName =  sysUser.getFullName();
                        }
                        taskOpinion.setExeFullname(fullName);
                    }
                    //获取候选人
                    else{
                        Set<TaskExecutor> set= taskUserService.getCandidateExecutors(task.getId());
                        Set<SysUser> sysUsers=new HashSet<>();
                        for(Iterator<TaskExecutor> it=set.iterator();it.hasNext();){
                            TaskExecutor taskExe=it.next();
                            if(taskExe==null){
                                continue;
                            }
                            Set<SysUser> users = taskExe.getSysUser();
                            for(SysUser user:users){
                                sysUsers.add(user);
                            }

                        }
                        if(taskOpinion.getCandidateUsers()==null){
                            taskOpinion.setCandidateUsers(new ArrayList<>());
                        }
                        taskOpinion.getCandidateUsers().addAll(sysUsers);
                    }
                }
            }
        }
        return opinions;
    }

    public TaskOpinion getOpinionByTaskIdUserId(String taskId, String userId) {
        return taskOpinionDao.getOpinionByTaskId(taskId,userId);
    }
}
